home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / slipsrc.zip / SLIP8250.ASM < prev    next >
Assembly Source File  |  1991-02-11  |  29KB  |  1,099 lines

  1. version    equ    5
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  6. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;16550 support ruthlessly stolen from Phil Karn's 8250.c. Bugs by Denis DeLaRoca
  8.  
  9. ;  Copyright, 1988, 1989, Russell Nelson
  10.  
  11. ;   This program is free software; you can redistribute it and/or modify
  12. ;   it under the terms of the GNU General Public License as published by
  13. ;   the Free Software Foundation, version 1.
  14. ;
  15. ;   This program is distributed in the hope that it will be useful,
  16. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ;   GNU General Public License for more details.
  19. ;
  20. ;   You should have received a copy of the GNU General Public License
  21. ;   along with this program; if not, write to the Free Software
  22. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. code    segment    word public
  25.     assume    cs:code, ds:code
  26.  
  27. ;8250 definitions
  28. ;Control/status register offsets from base address
  29. THR    equ    0        ;Transmitter holding register
  30. RBR    equ    0        ;Receiver buffer register
  31. DLL    equ    0        ;Divisor latch LSB
  32. DLM    equ    1        ;Divisor latch MSB
  33. IER    equ    1        ;Interrupt enable register
  34. IIR    equ    2        ;Interrupt ident register
  35. FCR    equ    2        ;16550 FIFO control register
  36. LCR    equ    3        ;Line control register
  37. MCR    equ    4        ;Modem control register
  38. LSR    equ    5        ;Line status register
  39. MSR    equ    6        ;Modem status register
  40.  
  41. ;8250 Line Control Register
  42. LCR_5BITS    equ    0    ;5 bit words
  43. LCR_6BITS    equ    1    ;6 bit words
  44. LCR_7BITS    equ    2    ;7 bit words
  45. LCR_8BITS    equ    3    ;8 bit words
  46. LCR_NSB        equ    4    ;Number of stop bits
  47. LCR_PEN        equ    8    ;Parity enable
  48. LCR_EPS        equ    10h    ;Even parity select
  49. LCR_SP        equ    20h    ;Stick parity
  50. LCR_SB        equ    40h    ;Set break
  51. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  52.  
  53. ;16550 FIFO control register values
  54. FIFO_ENABLE     equ     001h    ;Enable TX and RX fifo
  55. FIFO_CLR_RX     equ     002h    ;Clear RX fifo
  56. FIFO_CLR_TX     equ     004h    ;Clear TX fifo
  57. FIFO_START_DMA  equ     008h    ;Enable TXRDY/RXRDY pin DMA handshake
  58. FIFO_SIZE_1     equ     000h    ;RX fifo trigger levels
  59. FIFO_SIZE_4     equ     040h
  60. FIFO_SIZE_8     equ     080h
  61. FIFO_SIZE_14    equ     0c0h
  62. FIFO_SIZE_MASK  equ     0c0h
  63.  
  64. FIFO_TRIGGER_LEVEL equ FIFO_SIZE_4
  65. FIFO_SETUP         equ FIFO_ENABLE+FIFO_CLR_RX+FIFO_CLR_TX+FIFO_TRIGGER_LEVEL
  66. OUTPUT_FIFO_SIZE   equ 16
  67.  
  68. ;8250 Line Status Register
  69. LSR_DR    equ    1    ;Data ready
  70. LSR_OE    equ    2    ;Overrun error
  71. LSR_PE    equ    4    ;Parity error
  72. LSR_FE    equ    8    ;Framing error
  73. LSR_BI    equ    10h    ;Break interrupt
  74. LSR_THRE equ    20h    ;Transmitter line holding register empty
  75. LSR_TSRE equ    40h    ;Transmitter shift register empty
  76.  
  77. ;8250 Interrupt Identification Register
  78. IIR_IP        equ    1    ;0 if interrupt pending
  79. IIR_ID        equ    6    ;Mask for interrupt ID
  80. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  81. IIR_RDA        equ    4    ;Receiver data available interrupt
  82. IIR_THRE    equ    2    ;Transmitter holding register empty int
  83. IIR_MSTAT    equ    0    ;Modem status interrupt
  84. IIR_FIFO_TIMEOUT  equ   008h    ;FIFO timeout interrupt pending - 16550 only
  85. IIR_FIFO_ENABLED  equ   080h    ;FIFO enabled (FCR0 = 1) - 16550 only
  86.  
  87. ;8250 interrupt enable register bits
  88. IER_DAV    equ    1    ;Data available interrupt
  89. IER_TxE    equ    2    ;Tx buffer empty interrupt
  90. IER_RLS    equ    4    ;Receive line status interrupt
  91. IER_MS    equ    8    ;Modem status interrupt
  92.  
  93. ;8250 Modem control register
  94. MCR_DTR    equ    1    ;Data Terminal Ready
  95. MCR_RTS    equ    2    ;Request to Send
  96. MCR_OUT1 equ    4    ;Out 1 (not used)
  97. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  98. MCR_LOOP equ    10h    ;Loopback test mode
  99.  
  100. ;8250 Modem Status Register
  101. MSR_DCTS equ    1    ;Delta Clear-to-Send
  102. MSR_DDSR equ    2    ;Delta Data Set Ready
  103. MSR_TERI equ    4    ;Trailing edge ring indicator
  104. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  105. MSR_CTS equ    10h    ;Clear to send
  106. MSR_DSR equ    20h    ;Data set ready
  107. MSR_RI    equ    40h    ;Ring indicator
  108. MSR_RLSD equ    80h    ;Received line signal detect
  109.  
  110. ;Slip Definitions
  111. FR_END        equ    0c0h        ;Frame End
  112. FR_ESC        equ    0dbh        ;Frame Escape
  113. T_FR_END    equ    0dch        ;Transposed frame end
  114. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  115.  
  116.     public    int_no
  117. int_no        db    4,0,0,0        ; interrupt number.
  118. io_addr        dw    03f8h,0        ; I/O address for COM1.
  119. baud_rate    dw    12c0h,0        ; We support baud rates higher than 65535.
  120. baudclk        label    word
  121.         dd    115200        ;1.8432 Mhz / 16
  122. hardware_switch    db    0        ;if zero, don't use hardware handshaking.
  123. is_16550        db      0               ;0=no, 1=yes (try using fifo)
  124.  
  125.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  126. driver_class    db    6,0,0,0        ;from the packet spec
  127. driver_type    db    0,0,0,0        ;from the packet spec
  128. driver_name    db    'SLIP8250',0    ;name of the driver.
  129. driver_function    db    2
  130. parameter_list    label    byte
  131.     db    1    ;major rev of packet driver
  132.     db    9    ;minor rev of packet driver
  133.     db    14    ;length of parameter list
  134.     db    EADDR_LEN    ;length of MAC-layer address
  135.     dw    GIANT    ;MTU, including MAC headers
  136.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  137.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  138.     dw    0    ;(# of successive xmits) - 1
  139. int_num    dw    0    ;Interrupt # to hook for post-EOI
  140.             ;processing, 0 == none,
  141.  
  142.   ifdef debug
  143.     public recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  144.     public recv_buf_tail, recv_pkt_ready
  145.   endif
  146. recv_buf_size    dw    3000,0        ;receive buffer size
  147. recv_buf    dw    ?        ;->receive buffer
  148. recv_buf_end    dw    ?        ;->after end of buffer
  149. recv_buf_head    dw    ?        ;->next character to get
  150. recv_buf_tail    dw    ?        ;->next character to store
  151. recv_pkt_ready    dw    0        ; flag indicating a packet is ready
  152.  
  153.   ifdef debug
  154.     public send_buf
  155.   endif
  156. send_buf_size    dw    3000,0        ;send buffer size
  157. send_buf    dw    ?        ;->send buffer
  158. send_buf_end    dw    ?        ;->after end of buffer
  159. send_buf_head    dw    ?        ;->next character to get
  160. send_buf_tail    dw    ?        ;->next character to store
  161.  
  162.   ifdef debug
  163.     public packet_sem, pkt_send_sem, xmit_time
  164.   endif
  165. packet_sem    dw    0        ; semaphore for    packets received
  166. pkt_send_sem    dw    0        ; semaphore for    packets xmitted
  167. asyrxint_cnt    dw    0        ; loop counter in asyrxint
  168. xmit_time    dw    0        ; loop timer for asyrxint
  169.  
  170.     public    rcv_modes
  171. rcv_modes    dw    4        ;number    of receive modes in our table.
  172.         dw    0,0,0,rcv_mode_3
  173.  
  174.  
  175.     public    as_send_pkt
  176. ; The Asynchronous Transmit Packet routine.
  177. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  178. ;   interrupts possibly enabled.
  179. ; Exit with nc if ok, or else cy if error, dh set to error number.
  180. ;   es:di and interrupt enable flag preserved on exit.
  181. as_send_pkt:
  182.     ret
  183.  
  184.     public    drop_pkt
  185. ; Drop a packet from the queue.
  186. ; Enter with es:di -> iocb.
  187. drop_pkt:
  188.     assume    ds:nothing
  189.     ret
  190.  
  191.     public    xmit
  192. ; Process a transmit interrupt with the least possible latency to achieve
  193. ;   back-to-back packet transmissions.
  194. ; May only use ax and dx.
  195. xmit:
  196.     assume    ds:nothing
  197.     ret
  198.  
  199.  
  200.     public    send_pkt
  201. ;
  202. ; mod 7/25/89 John Grover
  203. ; - operates with interrupts on. Xmits one byte per interrupt
  204. ; - only turns transmitter buffer empty interrupt off when
  205. ; - all bytes of all packets are transmitted.
  206.  
  207. send_pkt:
  208. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  209. ;  (only if the high-performance bit is set in driver_function)
  210. ;enter with ds:si -> packet, cx = packet length.
  211. ;exit with nc if ok, or else cy if error, dh set to error number.
  212. ;called from telnet layer via software interrupt
  213.     assume    ds:nothing
  214.  
  215.     push    cs
  216.     pop    es
  217.     mov    di,send_buf_tail
  218.     sti                ; enable interrupts
  219.  
  220.     mov    al,FR_END        ;Flush out any line garbage
  221.     call    send_char
  222.  
  223. ;Copy input to output, escaping special characters
  224. send_pkt_1:
  225.     lodsb
  226.     cmp    al,FR_ESC        ;escape FR_ESC with FR_ESC and T_FR_ESC
  227.     jne    send_pkt_2
  228.     mov    al,FR_ESC
  229.     call    send_char
  230.     mov    al,T_FR_ESC
  231.     jmp    short send_pkt_3
  232. send_pkt_2:
  233.     cmp    al,FR_END        ;escape FR_END with FR_ESC and T_FR_END
  234.     jne    send_pkt_3
  235.     mov    al,FR_ESC
  236.     call    send_char
  237.     mov    al,T_FR_END
  238. send_pkt_3:
  239.     call    send_char
  240.     loop    send_pkt_1
  241.     mov    al,FR_END        ;terminate it with a FR_END
  242.     call    send_char
  243.     mov    send_buf_tail,di
  244.  
  245.     inc    pkt_send_sem        ; increment the semaphore
  246.     cmp    pkt_send_sem, 1        ; see if we need to enable
  247.                     ; xmit buffer empty interrupt
  248.     ja    send_pkt_end
  249.  
  250.     mov    ah,IER_TxE        ; enable xmit buffer empty interrupt
  251.     cmp    hardware_switch,0    ; should we do hardware handshaking?
  252.     je    send_pkt_4        ; no, just enable TxE.
  253.  
  254. ;Enable modem status and (maybe) transmitter buffer empty interrupt.
  255.     loadport
  256.     setport    MSR
  257.     mov    ah, IER_MS        ; always enable modem status interrupt
  258.     in    al, dx            ; check if clear to send
  259.     test    al, MSR_CTS
  260.     jz    send_pkt_4        ; no - won't enable xmit buffer empty interrupt
  261.  
  262.     or    ah,IER_TxE        ; yes - enable xmit buffer empty interrupt
  263.  
  264. send_pkt_4:
  265.     loadport
  266.     setport    IER
  267.     call    setbit            ; enable
  268.     cli
  269. send_pkt_end:
  270.     clc
  271.     ret
  272.  
  273. ;
  274. ; mod 7/25/89 John Grover
  275. ; - utilizes buffer pointers to ascertain if the
  276. ; - buffer has room for    another character
  277. ;
  278.  
  279. send_char:
  280. ;stuff the character in al into the transmit buffer, but only if there
  281. ;is enough room, otherwise ignore the char.
  282.     assume    ds:nothing
  283.  
  284.     cmp    di, send_buf_head    ;are we out of buffer?
  285.     jne    send_char_ok        ;no - continue
  286.     cmp    pkt_send_sem, 0        ;maybe - if no packets then no
  287.     jne    send_char_1        ;if there are packets then yes
  288.  
  289. send_char_ok:
  290.     stosb                ;store the char.
  291.     cmp    di,send_buf_end        ;do we need to wrap around?
  292.     jne    send_char_1        ;no.
  293.     mov    di,send_buf        ;yes - reload with beginning.
  294. send_char_1:
  295.     ret
  296.  
  297.  
  298.     public    get_address
  299. get_address:
  300. ;get the address of the interface.
  301. ;enter with es:di -> place to get the address, cx = size of address buffer.
  302. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  303.     assume    ds:code
  304.     mov    cx,0
  305.     clc
  306.     ret
  307.  
  308.  
  309.     public    set_address
  310. set_address:
  311. ;set the address of the interface.
  312. ;enter with es:di -> place to get the address, cx = size of address buffer.
  313. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  314.     assume    ds:nothing
  315.     clc
  316.     ret
  317.  
  318.  
  319. rcv_mode_3:
  320. ;receive mode 3 is the only one we support, so we don't have to do anything.
  321.     ret
  322.  
  323.  
  324.     public    set_multicast_list
  325. set_multicast_list:
  326. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  327. ;return nc if we set all of them, or cy,dh=error if we didn't.
  328.     mov    dh,NO_MULTICAST
  329.     stc
  330.     ret
  331.  
  332.  
  333.     public    get_multicast_list
  334. get_multicast_list:
  335. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  336. ;return    cy, NO_ERROR if we don't remember all of the addresses ourselves.
  337. ;return cy, NO_MULTICAST if we don't implement multicast.
  338.     mov    dh,NO_MULTICAST
  339.     stc
  340.     ret
  341.  
  342.  
  343.     public    terminate
  344. terminate:
  345.     ret
  346.  
  347.     public    reset_interface
  348. reset_interface:
  349. ;reset the interface.
  350.     assume    ds:code
  351.     ret
  352.  
  353.  
  354. ;called    when we    want to determine what to do with a received packet.
  355. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  356.     extrn    recv_find: near
  357.  
  358. ;called after we have copied the packet into the buffer.
  359. ;enter with ds:si ->the packet, cx = length of the packet.
  360.     extrn    recv_copy: near
  361.  
  362.     extrn    count_in_err: near
  363.     extrn    count_out_err: near
  364.  
  365.     public    recv
  366.  
  367. ;
  368. ; mod 7/25/89 John Grover
  369. ;
  370. ; - added code to check modem status change interrupt. If CTS is
  371. ; - low  turn off transmitter buffer empty interrupt. If CTS is
  372. ; - high turn it on.
  373.  
  374. recv:
  375. ;called from the recv isr.  All registers have been saved, and ds=cs.
  376. ;Upon exit, the interrupt will be acknowledged.
  377.     assume    ds:code
  378. recv_2:
  379.     loadport
  380.     setport    IIR
  381.     in    al,dx            ;any interrupts at all?
  382.     test    al,IIR_IP
  383.     jne    recv_1            ;no.
  384.     and    al,IIR_ID
  385.     cmp    al,IIR_RDA        ;Receiver interrupt
  386.     jne    recv_3
  387.     call    asyrxint
  388.     jmp    recv_2
  389. recv_3:
  390.     cmp    al,IIR_THRE        ;Transmit interrupt
  391.     jne    recv_5
  392.     call    asytxint
  393.     jmp    recv_2
  394. recv_5:
  395. ;process IIR_MSTAT here.
  396. ;  If CTS and packet ready then
  397. ;    enable the    transmit buffer empty interrupt
  398. ;  else
  399. ;    disable the transmit buffer empty interrupt
  400. ;
  401.     cmp    al, IIR_MSTAT
  402.     jne    recv_4
  403.     setport    MSR            ; make sure of CTS status
  404.     mov    ah, IER_TxE        ; get ready to alter xmit buffer empty interrupt
  405.     in    al, dx
  406.     test    al, MSR_CTS        ; is CTS bit set
  407.     jz    recv_5_1        ; no - disable xmit buffer empty int
  408.     cmp    pkt_send_sem, 0        ; yes - is there a packet to xmit
  409.     jbe    recv_2            ; no - all done here
  410.     setport    IER            ; yes - enable xmit buffer empty int
  411.     call    setbit
  412.     jmp    recv_2
  413.  
  414. recv_5_1:
  415.     setport    IER
  416.     call    clrbit
  417.     jmp    recv_2
  418.  
  419. recv_4:
  420. ;process IIR_RLS here
  421. recv_1:
  422.     ret
  423.  
  424.  
  425. ;Process 8250 receiver interrupts
  426. ;
  427. ; mod 7/25/89 John Grover
  428. ; - this branches off when bps < 9600. See asyrxint_a.
  429. ; - Above 9600 bps we go into a loop to process a packet at
  430. ; - a time. If not data ready for a certain amount of time,
  431. ; - the process exits and waits for the next byte. This certain
  432. ; - amount of time to wait depends on the bps and CPU processor speed
  433. ; - and is determined in the initialization of the driver.
  434. ; - Upon receiving the FR_END character for the first frame in the
  435. ; - buffer a semaphore is set which tells recv_frame to run.
  436.  
  437. asyrxint:
  438.  
  439.     push    ds            ; get set up for the routine
  440.     pop    es
  441.     xor    bx, bx
  442.     cmp    baud_rate, 9600         ; below 9600 we're strictly
  443.     jbe    asyrxint_a              ; interrupt driven
  444.     mov    bx, xmit_time
  445. asyrxint_a:
  446.     mov    di,recv_buf_tail
  447.     xor    bp, bp            ; set flag to indicate 1st char
  448.                     ; processed
  449.     mov    si, packet_sem          ; optimization
  450.     loadport
  451.     mov    ah, LSR_DR
  452.  
  453. asyrxint_again:
  454.     xor    cx, cx            ; initialize counter
  455.     setport    LSR
  456. asyrxint_in:
  457.     in    al,dx            ; check for data ready
  458.     test    al,LSR_DR
  459.     jnz    asyrxint_gotit        ; yes - break out of loop
  460.     inc    cx            ; no - increase loop counter
  461.     cmp    cx, bx            ; timeout?
  462.     jae    asyrxint_exit        ; yes - leave
  463.     jmp    asyrxint_in        ; no - keep looping
  464.  
  465. asyrxint_gotit:
  466.     setport    RBR
  467.     in    al,dx
  468.  
  469. ;Process incoming data;
  470. ; If buffer is full, we have no choice but
  471. ; to drop the character
  472.  
  473.     cmp    di,recv_buf_head    ; check for buffer collision
  474.     jne    asyrxint_ok        ; none - continue
  475.     or    si, si                  ; maybe - if there are packets
  476.     jnz    asyrxint_exit        ; yes exit
  477.  
  478. asyrxint_ok:
  479.     stosb
  480.  
  481.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  482.     jne    asyrxint_3        ; no.
  483.     mov    di,recv_buf        ; yes - wrap around.
  484.  
  485. asyrxint_3:
  486.     cmp    al,FR_END        ; might    this be    the end of a frame?
  487.     jne    asyrxint_reset        ; no - reset flag and loop
  488.     inc    si                      ; yes - indicate packet ready
  489.     cmp    si, 1                   ; determine if semaphore is <> 1
  490.     jne    asyrxint_chk_flg        ; yes - recv_frame must be active
  491.     inc    recv_pkt_ready          ; no - set flag to start recv_frame
  492.  
  493. asyrxint_chk_flg:
  494.     cmp    bp, 0                   ; was this the first char?
  495.     jne    asyrxint_1              ; no - exit handler
  496. asyrxint_reset:
  497.     inc    bp            ; set 1st character flag
  498.     jmp    asyrxint_again        ; get another character
  499.  
  500. asyrxint_exit:
  501. asyrxint_1:
  502.     mov    recv_buf_tail,di
  503.     mov    packet_sem, si
  504.  
  505.     ret
  506.  
  507.  
  508. ; --------------------------------------------------------------
  509. ;
  510. ;  recv_exiting
  511. ;
  512.     public    recv_exiting
  513. recv_exiting:
  514.     cmp    recv_pkt_ready, 1       ; is a packet ready?
  515.     jne    recv_isr_exit           ; no - skip to end
  516.     push    ax
  517.     push    bx
  518.     push    cx
  519.     push    dx
  520.     push    ds
  521.     push    es
  522.     push    bp
  523.     push    di
  524.     push    si
  525.     push    cs            ; point ds properly
  526.     pop    ds
  527.     mov    recv_pkt_ready,    0    ; reset flag
  528.     sti                ; enable interrupts
  529.  
  530.     call    recv_frame
  531.  
  532.     cli
  533.     pop    si
  534.     pop    di
  535.     pop    bp
  536.     pop    es
  537.     pop    ds
  538.     pop    dx
  539.     pop    cx
  540.     pop    bx
  541.     pop    ax
  542. recv_isr_exit:
  543.     ret
  544.  
  545.  
  546. ; --------------------------------------------------------------
  547. ;
  548. ;  recv_frame
  549. ;
  550. ; mod 7/25/89 John Grover
  551. ;
  552. ; - recv_frame now operates with interrupts on. It is triggered
  553. ; - by the recv_pkt_ready flag and continues until all bytes
  554. ; - in all packets in the buffer have been transmitted to the upper
  555. ; - layer.
  556. ;
  557.   ifdef debug
  558.     public recv_frame
  559.   endif
  560. recv_frame:
  561.     cmp    packet_sem, 0        ; should we do this?
  562.     jz    recv_frame_end        ; no - exit
  563.     mov    si,recv_buf_head    ;process characters.
  564.     xor    cx,cx            ;count up the size here.
  565. recv_frame_1:
  566.  
  567.     call    recv_char        ;get a char.
  568.     je    recv_frame_2        ;go if no more chars.
  569.     cmp    al,FR_ESC        ;an escape?
  570.     je    recv_frame_1        ;yes - don't count this char.
  571.     inc    cx            ;no - count this one.
  572.     jmp    recv_frame_1
  573. recv_frame_2:
  574.  
  575.     jcxz    recv_frame_3        ;count zero? yes - just free the frame.
  576. ;we don't need to set the type because none are defined for SLIP.
  577.     push    si            ;save si in case we reject it.
  578.     push    bx
  579.     mov    di,0            ;but we avoid any segment end bullshit.
  580.     mov    dl,cs:driver_class
  581.     call    recv_find        ;look up our type.
  582.     pop    bx
  583.     pop    si
  584.  
  585.     mov    ax,es            ;is this pointer null?
  586.     or    ax,di
  587.     je    recv_frame_3        ;yes - just free the frame.
  588.  
  589.     push    cx
  590.     push    es            ;remember where the buffer pointer is.
  591.     push    di
  592.  
  593.     mov    si,recv_buf_head    ;process characters.
  594. recv_frame_4:
  595.     call    recv_char
  596.     je    recv_frame_6        ;yes - we're all done.
  597.     cmp    al,FR_ESC        ;an escape?
  598.     jne    recv_frame_5        ;no - just store it.
  599.  
  600.     call    recv_char        ;get the next character.
  601.     je    recv_frame_6
  602.     cmp    al,T_FR_ESC
  603.     mov    al,FR_ESC        ;assume T_FR_ESC
  604.     je    recv_frame_5        ;yup, that's it    - store FR_ESC
  605.     mov    al,FR_END        ;nope, store FR_END
  606. recv_frame_5:
  607.     stosb                ;store the byte.
  608.     jmp    recv_frame_4
  609. recv_frame_6:
  610.     mov    recv_buf_head,si    ;we're skipped to the end.
  611.  
  612.     pop    si            ;now give the frame to the client.
  613.     pop    ds
  614.     pop    cx
  615.     assume    ds:nothing
  616.  
  617.     call    recv_copy
  618.     push    cs
  619.     pop    ds
  620.     assume    ds:code
  621.     jmp    recv_frame_end
  622.  
  623. recv_frame_3:
  624.     mov    recv_buf_head,si    ;remember the new starting point.
  625. recv_frame_end:
  626.     dec    packet_sem
  627.     cmp    packet_sem, 0        ; are there more packets ready?
  628.     ja    recv_frame              ; yes - execute again
  629.     ret
  630.  
  631.  
  632. ; --------------------------------------------------------------
  633. ;
  634. ;  recv_char
  635. ;
  636. ; mod 7/25/89 John Grover
  637. ; - Now    uses buffer pointers to determine if there are
  638. ; - characters left.
  639. ;
  640.  
  641. recv_char:
  642. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  643. ;return with nz, al = next char.  Return zr if there are no more chars in
  644. ;  this frame.
  645. ;
  646.     lodsb
  647.     cmp    si,recv_buf_end
  648.     jb    recv_char_1
  649.     mov    si,recv_buf
  650. recv_char_1:
  651.     mov    bx, recv_buf_tail
  652.     cmp    si, bx
  653.     je    recv_char_2
  654.     cmp    al,FR_END
  655. recv_char_2:
  656.     ret
  657.  
  658.  
  659. ;Handle 8250 transmitter interrupts
  660.  
  661. ; --------------------------------------------------------------
  662. ;
  663. ;  asytxint
  664. ;
  665. ; mod 7/25/89
  666. ; - Transmits one character and then exits. Upon last character
  667. ; - to transmit modem status and transmitter buffer empty interrupt
  668. ; - are disabled.
  669. ;
  670.  
  671. asytxint:
  672.  
  673. asytxint_2:
  674.  
  675. ;
  676. ; mod  3/16/90  Denis DeLaRoca
  677. ; - for 16550 fifo uart stuff up to 16 chars at a time
  678. ; - for  8250 uart can only output one char at a time
  679. ;
  680.     cmp    is_16550,1              ;have 16550 uart
  681.     jne    asytxint_8250           ;no, handle as 8250
  682.  
  683. asytxint_16550:
  684.     loadport
  685.     setport    THR
  686.     mov    cx,16                   ;fifo fill-loop counter
  687.     mov     si,send_buf_head        ;current head of buffer
  688. asytxint_next:
  689.     lodsb                ;fetch next char
  690.     cmp    si,send_buf_end        ;past end of buffer
  691.     jne     asytxint_fill
  692.     mov    si,send_buf        ;yes, wrap around 
  693. asytxint_fill:
  694.     out    dx,al            ;output char
  695.     cmp    si,send_buf_tail    ;any more chars to output
  696.     je      asytxint_no_more        ;none...
  697.     loop    asytxint_next        ;loop while fifo not full
  698.     mov    send_buf_head,si       ;save last char position used
  699.     jmp    asytxint_1        ;and exit
  700. asytxint_no_more:
  701.     mov     send_buf_head,si        ;save last char position used
  702.     jmp    asytxint_disable    ;go disable status interrupts
  703.  
  704. asytxint_8250:
  705.     mov    si,send_buf_head    ; yes - load one
  706.     lodsb                ;
  707.     cmp    si,send_buf_end        ;have we hit the end yet?
  708.     jne    asytxint_3        ;no.
  709.     mov    si,send_buf        ;yes - wrap around
  710. asytxint_3:
  711.     loadport
  712.     setport    THR
  713.     out    dx,al
  714.     mov    send_buf_head,si    ; store our location
  715.     cmp    si, send_buf_tail    ; more to xmit?
  716.     jne    asytxint_1        ; yes just exit
  717.  
  718. ;No more characters to transmit -- disable transmit interrupts.
  719.  
  720. asytxint_disable:
  721.     setport    IER            ;Disable transmit and modem
  722.     mov    ah,IER_TxE or IER_MS    ; status interrupts
  723.     call    clrbit
  724.     mov    pkt_send_sem, 0        ; indicate we're finished
  725. asytxint_1:
  726.     ret
  727.  
  728.  
  729. ;Set bit(s) in I/O port
  730. setbit:
  731. ;enter with dx = port, ah = bit to set.
  732.     in    al,dx
  733.     or    al,ah
  734.     out    dx,al
  735.     ret
  736.  
  737.  
  738. ;Clear bit(s) in I/O port
  739. clrbit:
  740. ;enter with dx = port, ah = bit to set.
  741.     in    al,dx
  742.     not    al            ;perform an and-not using DeMorgan's.
  743.     or    al,ah
  744.     not    al
  745.     out    dx,al
  746.     ret
  747.  
  748.  
  749. ;any code after this will not be kept after initialization.
  750. end_resident    label    byte
  751.  
  752.     public    usage_msg
  753. usage_msg    db    "usage: SLIP8250 [-n] [-d] [-w] packet_int_no [-h] [driver_class] [int_no]",CR,LF
  754.         db    "   [io_addr] [baud_rate]",CR,LF
  755.         db    "   [send_buf_size] [recv_buf_size]",CR,LF
  756.         db    "   -h enables hardware handshaking",CR,LF
  757.         db    "   The driver_class should be SLIP, KISS, AX.25, or a number.",CR,LF,'$'
  758.  
  759.     public    copyright_msg
  760. copyright_msg    db    "Packet driver for SLIP8250, version ",'0'+majver,".",'0'+version,CR,LF
  761.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  762.  
  763. approximate_msg    db    "Warning: This baud rate can only be approximated using the 8250",CR,LF
  764.         db    "because it is not an even divisor of 115200",CR,LF,'$'
  765.  
  766. is_16550_msg    db      "16550 Uart detected, FIFO will be used",CR,LF,'$'
  767.  
  768. class_name_ptr    dw    ?
  769. class_name    db    "Interface class ",'$'
  770. kiss_name    db    "KISS",CR,LF,'$'
  771. ax25_name    db    "AX.25",CR,LF,'$'
  772. slip_name    db    "SLIP",CR,LF,'$'
  773. int_no_name    db    "Interrupt number ",'$'
  774. io_addr_name    db    "I/O port ",'$'
  775. baud_rate_name    db    "Baud rate ",'$'
  776. send_buf_name    db    "Send buffer size ",'$'
  777. recv_buf_name    db    "Receive buffer size ",'$'
  778. unusual_com1    db    "That's unusual!  Com1 (0x3f8) usually uses interrupt 4!",CR,LF,'$'
  779. unusual_com2    db    "That's unusual!  Com2 (0x2f8) usually uses interrupt 3!",CR,LF,'$'
  780.  
  781.     extrn    set_recv_isr: near
  782.  
  783. ;enter with si -> argument string, di -> word to store.
  784. ;if there is no number, don't change the number.
  785.     extrn    get_number: near
  786.  
  787. ;enter with dx -> name of word, di -> dword to print.
  788.     extrn    print_number: near
  789.  
  790. ;enter with si -> argument string.
  791. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  792.     extrn    skip_blanks: near
  793.  
  794.  
  795.     public    parse_args
  796. parse_args:
  797. ;exit with nc if all went well, cy otherwise.
  798.     call    skip_blanks
  799.     cmp    al,'-'            ;did they specify a switch?
  800.     jne    not_switch
  801.     cmp    byte ptr [si+1],'h'    ;did they specify '-h'?
  802.     je    got_hardware_switch
  803.     stc                ;no, must be an error.
  804.     ret
  805. got_hardware_switch:
  806.     mov    hardware_switch,1
  807.     add    si,2            ;skip past the switch's characters.
  808.     jmp    parse_args        ;go parse more arguments.
  809. not_switch:
  810.     or    al,20h            ;convert to lower case (assuming letter).
  811.     cmp    al,'k'
  812.     jne    parse_args_2
  813.     mov    driver_class,10        ;KISS, from packet spec.
  814.     mov    dx,offset kiss_name
  815.     jmp    short parse_args_1
  816. parse_args_2:
  817.     cmp    al,'s'
  818.     jne    parse_args_3
  819.     mov    driver_class,6        ;SLIP, from packet spec.
  820.     mov    dx,offset slip_name
  821.     jmp    short parse_args_1
  822. parse_args_3:
  823.     cmp    al,'a'
  824.     jne    parse_args_4
  825.     mov    driver_class,9        ;AX.25, from packet spec.
  826.     mov    dx,offset ax25_name
  827.     jmp    short parse_args_1
  828. parse_args_4:
  829.     mov    di,offset driver_class
  830.     mov    bx,offset class_name
  831.     call    get_number
  832.     mov    class_name_ptr,0
  833.     jmp    short parse_args_6
  834. parse_args_1:
  835.     mov    class_name_ptr,dx
  836. parse_args_5:
  837.     mov    al,[si]            ;skip to the next blank or CR.
  838.     cmp    al,' '
  839.     je    parse_args_6
  840.     cmp    al,CR
  841.     je    parse_args_6
  842.     inc    si            ;skip the character.
  843.     jmp    parse_args_5
  844. parse_args_6:
  845.     mov    di,offset int_no
  846.     call    get_number
  847.     mov    di,offset io_addr
  848.     call    get_number
  849.     mov    di,offset baud_rate
  850.     call    get_number
  851.     mov    di,offset send_buf_size
  852.     call    get_number
  853.     mov    di,offset recv_buf_size
  854.     call    get_number
  855.     clc
  856.     ret
  857.  
  858.  
  859. ; --------------------------------------------------------------
  860. ;
  861. ;  etopen
  862. ;
  863. ; mod 7/25/89 John Grover
  864. ; - Contains a loop to determine a pseudo timeout for asyrxint.
  865. ; - The value is determined by transmitting characters in a
  866. ; - loop whose clock cycles are nearly the same as the "sister"
  867. ; - loop in asyrxint. The per character, maximum time used
  868. ; - basis which is then multiplied by a factor to achieve a timeout
  869. ; - value for the particular bps and CPU speed of the host.
  870.  
  871.     public    etopen
  872. etopen:
  873.     pushf
  874.     cli
  875. ;
  876. ; mod  3/16/90  Denis DeLaRoca
  877. ; - determine if 16550 uart is present
  878. ; - if so initialize fifo buffering
  879. ;
  880.     loadport
  881.     setport    FCR
  882.     mov    al,FIFO_ENABLE
  883.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_ENABLE)
  884.     setport    IIR
  885.     in    al,dx                   ;inportb(base+IIR)
  886.     and    al,IIR_FIFO_ENABLED     ;     & IIR_FIFO_ENABLED
  887.     cmp    al,IIR_FIFO_ENABLED    ;both bits must be on   NEW, 11/20/90
  888.     jnz    not_16550               ;nope, we don't have 16550 chip
  889.     mov    is_16550,1              ;yes, note fact
  890.     mov    al,FIFO_SETUP           ;and setup FIFO
  891.     setport    FCR
  892.     out    dx,al                   ;outportb(base+FCR,(char) FIFO_SETUP)
  893.  
  894.     mov    dx,offset is_16550_msg
  895.     mov    ah,9
  896.     int    21h            ;let user know about 16550
  897.  
  898. not_16550:
  899.     loadport            ;Purge the receive data buffer
  900.     setport    RBR
  901.     in    al,dx
  902.  
  903.     ;Set line control register: 8 bits, no parity
  904.     mov    al,LCR_8BITS
  905.     setport    LCR
  906.     out    dx,al
  907.  
  908.     ;Turn on receive interrupt enable in 8250, leave transmit
  909.     ; and modem status interrupts turned off for now
  910.     mov    al,IER_DAV
  911.     setport    IER
  912.     out    dx,al
  913.  
  914.     ;Set modem control register: assert DTR, RTS, turn on 8250
  915.     ; master interrupt enable (connected to OUT2)
  916.  
  917.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  918.     setport    MCR
  919.     out    dx,al
  920.  
  921. ;compute the divisor given the baud rate.
  922.     mov    dx,baudclk+2
  923.     mov    ax,baudclk
  924.     mov    bx,0
  925. asy_speed_1:
  926.     inc    bx
  927.     sub    ax,baud_rate
  928.     sbb    dx,baud_rate+2
  929.     jnc    asy_speed_1
  930.     dec    bx
  931.     add    ax,baud_rate
  932.     adc    dx,baud_rate+2
  933.     or    ax,dx
  934.     je    asy_speed_2
  935.  
  936.     mov    dx,offset approximate_msg
  937.     mov    ah,9
  938.     int    21h
  939.  
  940. asy_speed_2:
  941.  
  942.     loadport            ;Purge the receive data buffer
  943.     setport    RBR
  944.     in    al,dx
  945.  
  946.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  947.     setport    LCR
  948.     call    setbit
  949.  
  950.     mov    al,bl            ;Load the two bytes of the divisor.
  951.     setport    DLL
  952.     out    dx,al
  953.     mov    al,bh
  954.     setport    DLM
  955.     out    dx,al
  956.  
  957.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  958.     setport    LCR
  959.     call    clrbit
  960.  
  961.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  962.  
  963. ;set up the various pointers.
  964.     mov    dx,offset end_resident
  965.     mov    send_buf,dx
  966.     mov    send_buf_head,dx
  967.     mov    send_buf_tail,dx
  968.     add    dx,send_buf_size
  969.     mov    send_buf_end,dx
  970.  
  971.     mov    recv_buf,dx
  972.     mov    recv_buf_head,dx
  973.     mov    recv_buf_tail,dx
  974.     add    dx,recv_buf_size
  975.     mov    recv_buf_end,dx
  976.     push    dx            ;save the ending address.
  977.  
  978.     ; the following code attempts to determine a pseudo timeout
  979.     ; value    to use in the loop that waits for an incoming character
  980.     ; in asyrxint. The value returned in xmit_time is the number of
  981.     ; loops processed between characters - therefore the loop used below
  982.     ; is and should    remain similar to the loop used in asyrxint.
  983.  
  984.     xor    ax, ax            ; we'll send a 0
  985.     mov    ah, LSR_THRE
  986.     mov    cx, 10h            ; take the highest of 16 runs
  987.     xor    si, si            ; will hold highest value
  988.  
  989. xmit_time_start:
  990.  
  991.     xor    di, di            ; initialize counter
  992.     loadport
  993.     setport    THR            ; xmit a character
  994.     out    dx, al
  995.     setport    LSR               ; set up    to check for an empty buffer
  996.  
  997.     ; next is the loop actually being timed
  998.  
  999. xmit_time_top:
  1000.     in    al, dx
  1001.     test    al, ah
  1002.     jnz    xmit_time_done
  1003.     inc    di
  1004.     cmp    cx, cx            ; these next few instructions do nothing
  1005.     jmp    xmit_time_1        ;  except maintain similarity with the
  1006.                     ;  "sister" loop in asyrxint
  1007. xmit_time_1:
  1008.     jmp    xmit_time_top
  1009.  
  1010. xmit_time_done:                ; end of timed loop
  1011.  
  1012.  
  1013.  
  1014.     cmp    si, di            ; compare highest value with new value
  1015.     ja    xmit_time_end        ; no bigger - just loop
  1016.     mov    si, di            ; bigger - save it
  1017.  
  1018. xmit_time_end:
  1019.     loop    xmit_time_start        ; bottom of outer loop
  1020.  
  1021.     shl    si, 1            ; we'll wait 8 characters worth
  1022.     shl    si, 1
  1023.     shl    si, 1
  1024.     mov    xmit_time, si        ; retain largest value
  1025.  
  1026.     ; end of pseudo timer determination
  1027.  
  1028.     mov    al, int_no        ; Get board's interrupt vector
  1029.     add    al, 8
  1030.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1031.     jb    set_int_num        ; No.
  1032.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1033. set_int_num:
  1034.     xor    ah, ah            ; Clear high byte
  1035.     mov    int_num, ax        ; Set parameter_list int num.
  1036.  
  1037.     pop    dx            ;return the ending address.
  1038.     popf
  1039.     clc                ;indicate no errors.
  1040.     ret
  1041.  
  1042.     public    print_parameters
  1043. print_parameters:
  1044. ;echo our command-line parameters
  1045.     cmp    class_name_ptr,0
  1046.     je    echo_args_1
  1047.  
  1048.     mov    dx,offset class_name
  1049.     mov    ah,9
  1050.     int    21h
  1051.     mov    dx,class_name_ptr
  1052.     mov    ah,9
  1053.     int    21h
  1054.     jmp    short echo_args_2
  1055. echo_args_1:
  1056.     mov    di,offset driver_class
  1057.     mov    dx,offset class_name
  1058.     call    print_number
  1059. echo_args_2:
  1060.  
  1061.     mov    di,offset int_no
  1062.     mov    dx,offset int_no_name
  1063.     call    print_number
  1064.     mov    di,offset io_addr
  1065.     mov    dx,offset io_addr_name
  1066.     call    print_number
  1067.  
  1068.     cmp    io_addr,03f8h        ;is this com1?
  1069.     jne    ia_com2
  1070.     mov    dx,offset unusual_com1
  1071.     cmp    int_no,4        ;com1 usually uses int 1.
  1072.     jne    ia_unusual
  1073.     jmp    short ia_usual
  1074. ia_com2:
  1075.     cmp    io_addr,02f8h        ;is this com2?
  1076.     jne    ia_usual        ;no.
  1077.     mov    dx,offset unusual_com2
  1078.     cmp    int_no,3        ;com2 usually uses int 3.
  1079.     je    ia_usual
  1080. ia_unusual:
  1081.     mov    ah,9
  1082.     int    21h
  1083. ia_usual:
  1084.  
  1085.     mov    di,offset baud_rate
  1086.     mov    dx,offset baud_rate_name
  1087.     call    print_number
  1088.     mov    di,offset send_buf_size
  1089.     mov    dx,offset send_buf_name
  1090.     call    print_number
  1091.     mov    di,offset recv_buf_size
  1092.     mov    dx,offset recv_buf_name
  1093.     call    print_number
  1094.     ret
  1095.  
  1096. code    ends
  1097.  
  1098.     end
  1099.